#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "cmd_trie.h"
#include "../ftp/ftp.h"

int trie_insert(trie_t *trie,const char *cmd,cmd_func_ptr_t func){
    trie_t *p=trie;
    for(int i=0;cmd[i]!='\0';i++){
        if(!isalpha(cmd[i])){
            return -1;
        }
        int c=tolower(cmd[i])-'a';
        if(p->children[c]==NULL){
            p->children[c]=(trie_t*)calloc(1,sizeof(trie_t));
        }
        p=p->children[c];
    }
    p->func=func;
    return 0;
}

cmd_func_ptr_t trie_get_func(trie_t *trie,const char *cmd){
    trie_t *p=trie;
    for(int i=0;cmd[i]!='\0';i++){
        if(!isalpha(cmd[i])){
            return NULL;
        }
        int c=tolower(cmd[i])-'a';
        if(p->children[c]==NULL){
            return NULL;
        }
        p=p->children[c];
    }
    return p->func;
}


void *callback(tlv_t *tlv,int sockfd,uint8_t type,uint32_t length,const uint8_t *value,void *args){
    if(type==RESPONSE){
        printf("%s",((const char*)value));
        fflush(stdout);
    }
    return NULL;
}

void *func_exit(tlv_t *tlv,int sockfd,const char *arg){
    tlv_request(tlv,sockfd,REQUEST_CMD_EXIT,strlen(arg)+1,(const uint8_t*)arg,callback,NULL);
    return (void*)1;
}

void *func_cd(tlv_t *tlv,int sockfd,const char *arg){
    tlv_request(tlv,sockfd,REQUEST_CMD_CD,strlen(arg)+1,(const uint8_t*)arg,callback,NULL);
    return NULL;
}
void *func_pwd(tlv_t *tlv,int sockfd,const char *arg){
    tlv_request(tlv,sockfd,REQUEST_CMD_PWD,strlen(arg)+1,(const uint8_t*)arg,callback,NULL);
    return NULL;
}
void *func_ls(tlv_t *tlv,int sockfd,const char *arg){
    tlv_request(tlv,sockfd,REQUEST_CMD_LS,strlen(arg)+1,(const uint8_t*)arg,callback,NULL);
    return NULL;
}
void *func_mkdir(tlv_t *tlv,int sockfd,const char *arg){
    tlv_request(tlv,sockfd,REQUEST_CMD_MKDIR,strlen(arg)+1,(const uint8_t*)arg,callback,NULL);
    return NULL;
}
void *func_rmdir(tlv_t *tlv,int sockfd,const char *arg){
    tlv_request(tlv,sockfd,REQUEST_CMD_RMDIR,strlen(arg)+1,(const uint8_t*)arg,callback,NULL);
    return NULL;
}
void *func_remove(tlv_t *tlv,int sockfd,const char *arg){
    tlv_request(tlv,sockfd,REQUEST_CMD_REMOVE,strlen(arg)+1,(const uint8_t*)arg,callback,NULL);
    return NULL;
}
void *callback_puts(tlv_t *tlv,int sockfd,uint8_t type,uint32_t length,const uint8_t *value,void *args){
    if(length==1){
        if(send_file(sockfd,(const char*)args)==-1){
            perror("puts");
        }
    }
    return NULL;
}
void *func_puts(tlv_t *tlv,int sockfd,const char *arg){
    tlv_request(tlv,sockfd,REQUEST_CMD_PUTS,strlen(arg)+1,(const uint8_t*)arg,callback_puts,(void*)arg);
    return NULL;
}
void *callback_gets(tlv_t *tlv,int sockfd,uint8_t type,uint32_t length,const uint8_t *value,void *args){
    if(length==1){
        if(recv_file(sockfd,(const char*)args)==-1){
            perror("gets");
        }
    }
    return NULL;
}
void *func_gets(tlv_t *tlv,int sockfd,const char *arg){
    tlv_request(tlv,sockfd,REQUEST_CMD_GETS,strlen(arg)+1,(const uint8_t*)arg,callback_gets,(void*)arg);
    return NULL;
}

void init_func(trie_t *cmd_dict){
    bzero(cmd_dict,sizeof(trie_t));
    trie_insert(cmd_dict,"exit",func_exit);
    trie_insert(cmd_dict,"cd",func_cd);
    trie_insert(cmd_dict,"pwd",func_pwd);
    trie_insert(cmd_dict,"ls",func_ls);
    trie_insert(cmd_dict,"mkdir",func_mkdir);
    trie_insert(cmd_dict,"rmdir",func_rmdir);
    trie_insert(cmd_dict,"remove",func_remove);
    trie_insert(cmd_dict,"puts",func_puts);
    trie_insert(cmd_dict,"gets",func_gets);
}
